<template>
  <!-- :visible="visible"
      @update:visible = "visible = $event" -->
  <!-- 第一个bug： 先点击编辑，再点击同一个元素的新增， 数据有残留---- 通过resetFields解决 -->
  <!-- 第二个bug： 先点击新增，在点击同一个的编辑，没有请求 -->
  <!-- 第三个bug： 先点击新增，在点击同一个的编辑，在点击新增。 这个时候弹出框的下拉框会自动校验报错 -->
  <div class="add-dialog">
    <el-dialog
      :title="isEdit ? '编辑部门' : '新增部门'"
      :visible="visible"
      width="50%"
      @close="resetForm"
    >
      <el-form ref="ruleForm" :model="ruleForm" :rules="rules" label-width="100px" class="demo-ruleForm">
        <el-form-item label="部门名称" prop="name">
          <el-input v-model="ruleForm.name" />
        </el-form-item>
        <el-form-item label="部门编码" prop="code">
          <el-input v-model="ruleForm.code" />
        </el-form-item>
        <el-form-item label="部门负责人" prop="managerId">
          <el-select v-model="ruleForm.managerId" clearable placeholder="请选择部门负责人">
            <el-option v-for="item in managerList" :key="item.id" :label="item.username" :value="item.id" />
          </el-select>
        </el-form-item>
        <el-form-item label="部门介绍" prop="introduce">
          <el-input v-model="ruleForm.introduce" type="textarea" />
        </el-form-item>
        <el-form-item>
          <el-button type="primary" @click="submitForm">{{ isEdit? '更新':'新增' }}</el-button>
          <el-button @click="resetForm">取消</el-button>
        </el-form-item>
      </el-form>
    </el-dialog>
  </div>
</template>

<script>
import {
  simpleListRequest,
  addDepartmentRequest,
  getDepartmentDetailRequest,
  updateDepartmentRequest }
from '@/api/department'

export default {
  props: {
    visible: {
      type: Boolean,
      required: true
    },
    list: {
      type: Array,
      required: true
    },
    currentId: {
      type: [Number, String],
      required: true
    },
    isEdit: {
      type: Boolean,
      required: true
    }
  },
  data() {
    const validatorName = (rules, value, callback) => {
      // 我们这个校验的函数里面  访问this.list 没有异步导致的空数组问题，
      // 因为的等我们打开弹出框，触发校验的时候，别人父组件的请求早就结束了，父向子单向数据流
      // 会自动将最新的值传递给子组件，所以这里访问的list就是最新的 list数组
      // 业务校验的时候，要先区分 编辑和新增两个状态，因为编辑的时候，名称可以重复
      let tmpArr = this.list
      if (this.isEdit) {
        tmpArr = this.list.filter(item => item.id !== this.currentId)
      }
      // debugger
      if (tmpArr.some((item) => item.name === value)) {
        callback(new Error('当前部门名称已存在，请重新输入'))
        return
      }
      callback()
    }

    const validatorCode = (rules, value, callback) => {
      let tmpArr = this.list
      if (this.isEdit) {
        tmpArr = this.list.filter(item => item.id !== this.currentId)
      }
      if (tmpArr.some((item) => item.code === value)) {
        callback(new Error('当前部门编码已存在，请重新输入'))
        return
      }
      callback()
    }
    return {
      ruleForm: {
        name: '',
        code: '',
        introduce: '',
        managerId: ''
      },
      rules: {
        name: [
          // 基本校验规则
          { required: true, message: '请填写部门名称', trigger: 'blur' },
          { min: 1, max: 50, message: '部门名称必须是1-50个字符', trigger: 'blur' },
          // 业务校验规则 --- 名称不能重复
          { validator: validatorName, trigger: 'blur' }
        ],
        code: [
          { required: true, message: '请填写部门编码', trigger: 'blur' },
          { min: 1, max: 50, message: '部门编码必须是1-50个字符', trigger: 'blur' },
          { validator: validatorCode, trigger: 'blur' }
        ],
        introduce: [
          { required: true, message: '请填写部门介绍', trigger: 'blur' },
          { min: 1, max: 300, message: '部门编码必须是1-300个字符', trigger: 'blur' }
        ],
        managerId: [
          { required: true, message: '请选择部门负责人', trigger: 'change' }
        ]
      },
      managerList: []
    }
  },
  watch: {
    // 如果在js里面想要获取最新的list值，需要使用 wathc监听数据的变化
    // 等请求结束以后，里面触发watch的回调函数
    // 总结： 如果想一开始加载组件就访问 最新的list数组，必须在wathc里面，不能在created钩子函数里面
    list(newVal, oldVal) {
      // console.log('WATCH函数', newVal, oldVal)
    },
    // 每当currentId值一发生改变，就会执行这个函数。 要将这个值是 空字符串的情况 排出来，不发请求
    async currentId(newVal) {
      if (this.isEdit && newVal) {
        // 必须是编辑状态  以及 当前的id有值的时候 才发请求
        const { data } = await getDepartmentDetailRequest(newVal)
        this.ruleForm = data
        delete this.ruleForm.managerName
        // this.ruleForm.name = data.name
        // this.ruleForm.code = data.code
        // this.ruleForm.introduce = data.introduce
        // this.ruleForm.managerId = data.managerId
      }
    }
  },
  // 弹出框的created不需要 打开弹窗就已经执行完毕了
  created() {
    // list数据在父组件里面 是经过了请求以后，将list值重新修改了，
    // 但是created在初始阶段已经执行完毕，所以这里打印的list就是一个 空数组
    // console.log(222, this.currentId)
    this.simpleList()
  },
  methods: {
    close() {
      // 因为有编辑会修改 ruleForm对象的结构，给他添加了很多属性，这样新增就有bug了
      // 所以在关闭弹出框的时候，需要将数据恢复到初始状态
      // 像下面这样写没问题，但是属性如果很多的时候，就很复杂，并且其他的无用属性还没有delete
      // this.ruleForm.name = ''
      // this.ruleForm.code = ''
      // this.ruleForm.introduce = ''
      // this.ruleForm.managerId = ''
      // delete this.rul.zxxx
      // this.$options 是当前组件 初始的配置对象，里面有很多默认的属性 data methods等等。我们就利用data函数重新调用，赋值给初始值
      this.ruleForm = this.$options.data().ruleForm
      console.log(this.$options)

      // 不能在子组件写 this.currentId === ''  因为这个数据是父组件的，子组件不能直接修改，要通知父组件
      this.$emit('RESET_PROPS')
      this.$emit('update:visible', false)
    },
    async simpleList() {
      const res = await simpleListRequest()
      this.managerList = res.data
    },
    submitForm() {
      this.$refs.ruleForm.validate(async value => {
        if (value) {
          // 证明所有校验成功，开始发请求
          // console.log(this.ruleForm)
          // 怎么样合并对象， this.ruleForm只有4个属性，我们还有个pid属性需要加进去
          // 两个方式合并对象  {...this.ruleForm, pid: 10}
          // Object.assign(this.ruleForm, {pid: 10})
          if (this.isEdit) {
            await updateDepartmentRequest(this.ruleForm)
          } else {
            await addDepartmentRequest({ ...this.ruleForm, pid: this.currentId })
          }
          this.resetForm()
          // 添加请求结束以后，要刷新页面，本质就是将树形组件的数据重新发个请求
          this.$emit('ADD_SUCCESS')
        }
      })
    },
    resetForm() {
      this.$refs.ruleForm.resetFields()
      this.close()
    }
  }
}
</script>

<style lang="scss" scoped>
.add-dialog {
  .el-select {
    width: 100%;
  }
}

</style>
